/**
 *  test_mem.c - Test codes for memory management and its functions.
 *               It runs on Windows or Linux.
 *
 *  Copyright (C) 2008  ZhangHu
 *  All rights reserved.
 *  E-MAIL: anmnmnly@gmail.com
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "test_mem.h"
#include "kernel/mem.c"
#include "kernel/list.c"


#define NR 1000

char *mem_array[NR];


static void test_kfree(void)
{
    void *_pfree = 0;

    /* Tested function call */
    kfree(_pfree);
}



static void test_kmalloc_0(void)
{
    /* Initializing argument 1 (Size) */
    word_t _Size = 0;

    /* Tested function call */
    void *_result = kmalloc(_Size);
    CU_ASSERT_PTR_NULL(_result);
}



static void test_kmalloc_1(void)
{
    /* Initializing argument 1 (Size) */
    word_t _Size = ~0;

    /* Tested function call */
    void *_result = kmalloc(_Size);
    CU_ASSERT_PTR_NULL(_result);
}



static void test_kmalloc_2(void)
{
    /* Initializing argument 1 (Size) */
    word_t _Size = -1;

    /* Tested function call */
    void *_result = kmalloc(_Size);
    CU_ASSERT_PTR_NULL(_result);
}



static void test_kmalloc_3(void)
{
    /* Initializing argument 1 (Size) */
    word_t _Size = 1;

    /* Tested function call */
    void *_result = kmalloc(_Size);
    CU_ASSERT_PTR_NOT_NULL(_result);
    kfree(_result);
}



static void test_kmemset(void)
{
    /* Initializing argument 1 (buffer) */
    char _buffer[100];

    /* Initializing argument 2 (ch) */
    char_t _ch = 'z';

    /* Initializing argument 3 (count) */
    uword_t _count = 100;

    /* Tested function call */
    kmemset(0, _ch, _count);
    kmemset(_buffer, _ch, _count);

    CU_ASSERT_EQUAL(_buffer[99], 'z');
    CU_ASSERT_EQUAL(_buffer[0], 'z');
}



static void test_mem_malloc_space(void) {
    char *str = NULL;
    int value = 0;
    int i;

    for(i=0; i<NR; i++) {
        value = 1 + rand() % (MEM_SIZE - 1);
        if((str = (char*)kmalloc(value * sizeof(char))) == NULL) {
            continue;
        }
        mem_array[i] = str;
    }
}



static void test_mem_free_space(void) {
    int i;

    for(i=0; i<NR; i++) {
        if(mem_array[i] != NULL) {
            kfree(mem_array[i]);
            mem_array[i] = NULL;
        }
    }
}



/* return free size of memory */
static int test_mem_stat_free_size(void) {
    int size = 0;
    page_t *page = NULL;
    page = kgetmemlist();

    while(page != NULL) {
        if(page->status == MEM_FREE) {
            size += page->size;
        }
        page = page->mem_down;
    }

    return size;
}



static void test_mem_malloc_free_bulk(void) {
    int i, size = 0;

    for(i=0; i<NR; i++) {
        test_mem_malloc_space();
        test_mem_free_space();
    }

    size = test_mem_stat_free_size();
    CU_ASSERT_EQUAL(size, MEM_SIZE);
}



static void test_mem_malloc_border(void) {
    int size = 0;
    char *str = NULL;

    str = kmalloc(0);
    CU_ASSERT_PTR_NULL(str);
    size = test_mem_stat_free_size();
    CU_ASSERT_EQUAL(size, MEM_SIZE);

    str = kmalloc(MEM_SIZE - sizeof(page_t));
    CU_ASSERT_PTR_NOT_NULL(str);
    size = test_mem_stat_free_size();
    CU_ASSERT_EQUAL(size, 0);

    kfree(str);
    size = test_mem_stat_free_size();
    CU_ASSERT_EQUAL(size, MEM_SIZE);
}



int test_mem_init(void) {
    int i;

    printf("memory management test ...\n\n");
    for(i=0; i<NR; i++) {
        mem_array[i] = NULL;
    }

    initmem();

    return(0);
}



int test_mem_clean(void) {
    printf("memory management test is over!\n\n");
	return(0);
}



CU_TestInfo test_mem_cases[] = {
    {"test_kfree", test_kfree},
    {"test_kmalloc_0", test_kmalloc_0},
    {"test_kmalloc_1", test_kmalloc_1},
    {"test_kmalloc_2", test_kmalloc_2},
    {"test_kmalloc_3", test_kmalloc_3},
    {"test_kmemset", test_kmemset},
    {"test_mem_malloc_free_bulk", test_mem_malloc_free_bulk},
    {"test_mem_malloc_border", test_mem_malloc_border},
    CU_TEST_INFO_NULL
};